<?php
/**
 * 核心类库
 * @author wuwenbin <wenbin.wu@foxmail.com>
 * @license http://opensource.org/licenses/MIT The MIT License
 */

//  全局配置类
class config {
    // 配置数据
    protected static $_data = array();
    // 修改配置
    public static function set($key, $value = null) {
        if(!is_array($key)) $key = array($key => $value);
        foreach($key as $k => $v) {
            if(is_array($v) && isset(self::$_data[$k]) && is_array(self::$_data[$k])) {
                self::$_data[$k] = array_merge(self::$_data[$k], $v);
            } else {
                self::$_data[$k] = $v;
            }
        }
    }
    // 获取配置
    public static function get($key = null, $key2 = null) {
        if($key === null) {
            return self::$_data;
        } elseif(is_array($key)) {
            $data = array();
            foreach($key as $v) {
                $data[$v] = isset(self::$_data[$Key]) ? self::$_data[$key] : null;
            }
            return $data;
        } else {
            $value = isset(self::$_data[$key]) ? self::$_data[$key] : null;
            if($key2 !== null) $value = isset($value[$key2]) ? $value[$key2] : null;
            return $value;
        }
    }
}

// mysql数据库操作类
class mysql {
    // 数据库连接配置
    protected static $_config = array();
    // 数据库连接资源
    protected static $_instance = array();
    // 查询错误信息
    protected static $_error = "";
    // 查询语句
    protected static $_sql = "";
    // 查询开始时间
    protected static $_start_time = "0 0";
    // 查询结束时间
    protected static $_finish_time = "0 0";
    // 查询日志回调函数
    public static $log_callback = "";
    // 添加数据库
    public static function add_db($config) {
        if(!is_array($config) || empty($config)) {
            return false;
        }
        $first = reset($config);
        if(!is_array($first)) {
            $config = array($config);
        }
        foreach($config as $v) {
            $db_id = isset($v["id"]) ? $v["id"] : 0;
            $data["host"] = isset($v["host"]) ? $v["host"] : "127.0.0.1";
            $data["port"] = isset($v["port"]) ? $v["port"] : "3306";
            $data["user"] = isset($v["user"]) ? $v["user"] : "root";
            $data["pass"] = isset($v["pass"]) ? $v["pass"] : "";
            $data["name"] = isset($v["name"]) ? $v["name"] : "";
            $data["charset"] = isset($v["charset"]) ? $v["charset"] : "utf8";
            self::remove_db($db_id);
            self::$_config[$db_id] = $data;
        }
        return true;
    }
    // 删除数据库
    public static function remove_db($db_id) {
        if(isset(self::$_config[$db_id])) unset(self::$_config[$db_id]);
        if(isset(self::$_instance[$db_id])) unset(self::$_instance[$db_id]);
    }
    // sql语句查询
    public static function query($sql, $db_id = 0) {
        self::$_sql = $sql;
        if(!self::_init_db($db_id)) {
            return false;
        }
        $handle = self::$_instance[$db_id];
        self::$_start_time = microtime();
        $result = mysql_query($sql, $handle);
        self::$_finish_time = microtime();
        if(!$result) {
            self::$_error = mysql_error($handle);
            return false;
        }
        // 记录日志
        if(is_callable(self::$log_callback)) {
            call_user_func(self::$log_callback, self::get_query_info());
        }
        // 如果想自行处理结果集,可以在sql语句前添加空格(" ")
        if(preg_match('/^insert/is', $sql)) {
            $ret = (int)mysql_insert_id($handle);
            if(!$ret) $ret = (int)mysql_affected_rows($handle);
            return $ret;
        }
        if(preg_match('/^(update|delete)/is', $sql)) {
            return (int)mysql_affected_rows($handle);
        }
        if(preg_match('/^(select|show)/is', $sql)) {
            $ret = array();
            while($row = mysql_fetch_assoc($result)) $ret[] = $row;
            return $ret;
        }
        return $result;
    }
    // 初始化数据库
    protected static function _init_db($db_id) {
        if(!isset(self::$_config[$db_id])) {
            self::$_error = "无此数据库配置信息";
            return false;
        }
        if(isset(self::$_instance[$db_id])) return true;
        $p = self::$_config[$db_id];
        $handle = mysql_connect($p["host"].":".$p["port"], $p["user"], $p["pass"], true);
        if(!$handle) {
            self::$_error = "连接数据库失败";
            return false;
        }
        if(!mysql_select_db($p["name"], $handle)) {
            self::$_error = mysql_error($handle);
            return false;
        }
        mysql_query("set names ".$p["charset"]);
        self::$_instance[$db_id] = $handle;
        return true;
    }
    // 获取查询信息
    public static function get_query_info() {
        $data["sql"] = self::$_sql;
        $data["error"] = self::$_error;
        $st = explode(" ", self::$_start_time);
        $ft = explode(" ", self::$_finish_time);
        $data["query_time"] = $ft[0] + $ft[1] - $st[0] - $st[1];
        $data["query_time"] = number_format($data["query_time"], 4, ".", "");
        return $data;
    }
    // 获取单条记录
    public static function get_one($sql, $db_id = 0) {
        $res = self::query($sql, $db_id);
        if(is_array($res) && !empty($res)) {
            return $res[0];
        } else {
            return null;
        }
    }
    // 获取错误信息
    public static function get_error() {
        return self::$_error;
    }
}

// 简单模版类(修改自initphp)
class template {
    // 模板基目录
    public static $path = "./";
    // 模板编译缓存文件
    public static $cache_path = "./";
    // 是否强制模板编译
    public static $force_compile = false;
    // 模板定界符
    protected static $_tag = array("<!--{", "}-->");
    // 赋值数据
    protected static $_data = array();
    // 错误信息
    protected static $_error = "";
    // 变量赋值
    public static function assign($key, $value = null) {
        if(is_array($key)) {
            self::$_data = array_merge(self::$_data, $key);
        } else {
            self::$_data[$key] = $value;
        }
    }
    // 获取错误信息
    public static function get_error() {
        return self::$_error;
    }
    // 获取赋值数据
    public function get_assign_data($key = null) {
        if($key === null) return self::$_data;
        return isset(self::$_data[$key]) ? self::$_data[$key] : null;
    }
    // 输出模板
    public static function display($tpl, $return = false) {
        $__CORE_TPL__ = $tpl;
        $__CORE_RET__ = $return;
        if(!self::_compile($__CORE_TPL__)) return false;
        foreach(self::$_data as $k => $v) $$k = $v;
        defined("TPL_INC") || define("TPL_INC", 1);
        if(!$__CORE_RET__) {
            include(self::_get_compiled_filename($__CORE_TPL__));
        } else {
            ob_start();
            include(self::_get_compiled_filename($__CORE_TPL__));
            return ob_get_clean();
        }
    }
    // 获取编译出的缓存文件名
    protected static function _get_compiled_filename($tpl) {
        return rtrim(self::$cache_path, "/")."/".$tpl.".cache.php";
    }
    // 模板编译
    protected static function _compile($tpl) {
        $left = self::$_tag[0];
        $right = self::$_tag[1];
        $tpl_file = rtrim(self::$path, "/")."/".$tpl;
        if(!is_file($tpl_file)) {
            self::$_error = "模板文件({$tpl_file})不存在";
            return false;
        }
        $is_compile = false;
        $c_file = self::_get_compiled_filename($tpl);
        if(!is_file($c_file) || filemtime($c_file) <= filemtime($tpl_file) || self::$force_compile) {
            $template = file_get_contents($tpl_file);
            preg_match_all("/(".$left."layout:)(.+)(".$right.")/U", $template, $matches);
            foreach($matches[2] as $v) {
                if(!self::_compile($v)) return false;
            }
            foreach ($matches[0] as $k => $v) {
                $replace = "<?php include('".self::_get_compiled_filename($matches[2][$k])."');?>";
                $template = str_replace($v, $replace, $template);
            }
            // if操作
            $template = preg_replace("/".$left."if([^{]+?)".$right."/", "<?php if \\1 { ?>", $template);
            $template = preg_replace("/".$left."else".$right."/", "<?php } else { ?>", $template);
            $template = preg_replace("/".$left."elseif([^{]+?)".$right."/", "<?php } elseif \\1 { ?>", $template);
            // foreach操作
            $template = preg_replace("/".$left."foreach([^{]+?)".$right."/", "<?php foreach \\1 { ?>", $template);
            $template = preg_replace("/".$left."\/foreach".$right."/", "<?php } ?>", $template);
            // for操作
            $template = preg_replace("/".$left."for([^{]+?)".$right."/", "<?php for \\1 { ?>", $template);
            $template = preg_replace("/".$left."\/for".$right."/", "<?php } ?>", $template);
            // 输出变量
            $template = preg_replace("/".$left."(\\$[a-zA-Z_\x7f-\xff][a-zA-Z0-9_$\x7f-\xff\[\]\'\']*)".$right."/", "<?php echo \\1;?>", $template);
            // 常量输出
            $template = preg_replace("/".$left."([A-Z_\x7f-\xff][A-Z0-9_\x7f-\xff]*)".$right."/s", "<?php echo \\1;?>", $template);
            // 输出函数
            $template = preg_replace("/".$left.":(\w+[^{]+?)".$right."/s", "<?php echo \\1;?>", $template);
            // 标签解析
            $template = preg_replace("/".$left."\/if".$right."/", "<?php } ?>", $template);
            // 替换所有标签
            $template = preg_replace(array("/".$left."/", "/".$right."/"), array("<?php ", " ?>"), $template);
            // 添加头部信息
            $template = "<?php if(!defined('TPL_INC')) {exit('Access Denied!');} ?>".$template;
            $base_dir = dirname($c_file);
            if(!is_dir($base_dir)) mkdir($base_dir, 0777, true);
            if(!file_put_contents($c_file, $template)) {
                self::$_error = "模板编译缓存文件{$c_file}保存失败";
                return false;
            }
        }
        return true;
    }
}

// 文件缓存类
class file_cache {
    // 数据缓存
    protected static $_cache = array();
    // 缓存保存路径
    public static $path = "./";
    // 缓存文件后缀
    public static $suffix = ".cache.php";
    // 写入缓存
    public static function set($name, $value) {
        $file = self::$path."/".$name.self::$suffix;
        $path = dirname($file);
        if(!is_dir($path)) {
            mkdir($path, 0777, true);
        }
        if(@file_put_contents($file, "<?php exit; ?>".json_encode($value))) {
            if(isset(self::$_cache[$file])) unset(self::$_cache[$file]);
            return true;
        } else {
            return false;
        }
    }
    // 读取缓存
    public static function get($name) {
        $file = self::$path."/".$name.self::$suffix;
        if(isset(self::$_cache[$file])) return self::$_cache[$file];
        if(!is_file($file)) {
            return null;
        } else {
            $value = json_decode(substr(file_get_contents($file), 14), true);
            return $value;
        }
    }
    // 删除缓存
    public static function remove($name) {
        $file = self::$path."/".$name.self::$suffix;
        if(is_file($file)) unlink($file);
    }
}

// 文件日志类
class file_log {
    // 模式:单一文件
    const mode_default = 0;
    // 模式:按天分割
    const mode_day = 1;
    // 模式:按周分割
    const mode_week = 2;
    // 模式:按月分割
    const mode_month = 3;
    // 日志保存路径
    public static $path = "./";
    // 日志文件后缀
    public static $suffix = ".log";
    // 日志模式
    public static $mode = 0;
    // 日志格式
    public static $format = "[{time}] {data}\n";
    // 追加方式保存日志
    public static function save($name, $data, $mode = null) {
        if(is_null($mode)) {
            $mode = self::$mode;
        }
        $timestamp = time();
        switch($mode) {
            case self::mode_day:
                $tag = date("_Y-m-d", $timestamp);
                break;
            case self::mode_week:
                $tag = date("_Y", $timestamp)."-w-".date("W", $timestamp);
                break;
            case self::mode_month:
                $tag = $date("_Y-m", $timestamp);
                break;
            default:
                $tag = "";
        }
        $file = self::$path."/".$name.$tag.self::$suffix;
        $path = dirname($file);
        if(!is_dir($path)) {
            mkdir($path, 0777, true);
        }
        $time = date("Y-m-d H:i:s", $timestamp);
        if(is_array($data)) $data = print_r($data, true);
        $data = trim($data);
        $log = str_replace(array("{time}", "{data}"), array($time, $data), self::$format);
        if(@file_put_contents($file, $log, FILE_APPEND)) {
            return true;
        } else {
            return false;
        }
    }
}

// http请求类(基于curl)
class http {
    // curl配置列表
    protected static $_opt = array();
    // 错误信息
    protected static $_error = "";
    // 设置curl配置
    public static function set_opt($key, $value) {
        if(!is_array($key)) $key = array($key => $value);
        foreach($key as $k => $v) {
            self::$_opt[$k] = $v;
        }
    }
    // 获取错误信息
    public static function get_error() {
        return self::$_error;
    }
    // 发送http请求
    public static function request($url, $data = null, $timeout = 20) {
        $curl = curl_init($url);
        if($data !== null) {
            curl_setopt($curl, CURLOPT_POST, 1);
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
        }
        curl_setopt($curl, CURLOPT_TIMEOUT, (int)$timeout);
        curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, 0);
        curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
        foreach(self::$_opt as $k => $v) {
            curl_setopt($curl, $k, $v);
        }
        $res = curl_exec($curl);
        if($res === false) {
            self::$_error = curl_errno($curl).":".curl_error($curl);
        }
        curl_close($curl);
        return $res;
    }
}

// ftp文件操作类
class file_ftp {
    // ftp连接配置
    protected static $_config = array();
    // ftp连接资源
    protected static $_instance = array();
    // 查询错误信息
    protected static $_error = "";
    // 添加ftp服务器
    public static function add_server($config) {
        if(!is_array($config)) {
            return false;
        }
        $first = array_slice($config, 0, 1);
        if(!is_array($first)) {
            $config = array($config);
        }
        foreach($config as $v) {
            $server_id = isset($v["id"]) ? $v["id"] : 0;
            $data["host"] = isset($v["host"]) ? $v["host"] : "127.0.0.1";
            $data["port"] = isset($v["port"]) ? $v["port"] : "21";
            $data["user"] = isset($v["user"]) ? $v["user"] : "anonymous";
            $data["pass"] = isset($v["pass"]) ? $v["pass"] : "";
            $data["timeout"] = isset($v["timeout"]) ? $v["timeout"] : 10;
            self::remove_server($server_id);
            self::$_config[$server_id] = $data;
        }
        return true;
    }
    // 删除ftp服务器
    public static function remove_server($server_id) {
        if(isset(self::$_config[$server_id])) unset(self::$_config[$server_id]);
        if(isset(self::$_instance[$server_id])) unset(self::$_instance[$server_id]);
    }
    // 获取错误信息
    public static function get_error() {
        return self::$_error;
    }
    // 初始化ftp连接
    protected static function _init($server_id) {
        if(!isset(self::$_config[$server_id])) {
            self::$_error = "无此ftp服务器配置信息";
            return false;
        }
        if(isset(self::$_instance[$server_id])) return true;
        $c = self::$_config[$server_id];
        $link = ftp_connect($c["host"], $c["port"], $c["timeout"]);
        if(!$link) {
            self::$_error = "连接ftp服务器失败";
            return false;
        }
        if(!ftp_login($link, $c["user"], $c["pass"])) {
            self::$_error = "登录ftp服务器失败";
            return false;
        }
        self::$_instance[$server_id] = $link;
        return true;
    }
    // 保存文件到ftp服务器
    public static function save($local, $remote, $server_id = 0) {
        if(!is_file($local)) {
            self::$_error = "本地文件不存在";
            return false;
        }
        if(!self::_init($server_id)) return false;
        $link = self::$_instance[$server_id];
        @ftp_chdir($link, "/");
        $dirs = explode("/", trim(dirname(trim($remote)), "/"));
        foreach($dirs as $v) {
            if(strlen($v) < 1) continue;
            ftp_mkdir($link, $v);
            if(!@ftp_chdir($link, $v)) {
                self::$_error = "ftp服务器创建目录失败";
                return false;
            }
        }
        @ftp_chdir($link, "/");
        if(!ftp_put($link, $remote, $local, FTP_BINARY)) {
            self::$_error = "上传文件到ftp服务器失败";
            return false;
        }
        return true;
    }
    // 删除ftp服务器文件
    public static function remove($remote, $server_id = 0) {
        if(!self::_init($server_id)) return false;
        $link = self::$_instance[$server_id];
        @ftp_chdir($link, "/");
        if(ftp_size($link, $remote) == -1) {
            self::$_error = "文件不存在ftp服务器上";
            return false;
        }
        return ftp_delete($link, $remote);
    }
    // 获取ftp服务器文件
    public static function get($local, $remote, $server_id = 0) {
        if(!self::_init($server_id)) return false;
        $link = self::$_instance[$server_id];
        @ftp_chdir($link, "/");
        if(ftp_size($link, $remote) == -1) {
            self::$_error = "文件不存在ftp服务器上";
            return false;
        }
        return ftp_get($link, $local, $remote, FTP_BINARY);
    }
}

// 计时器
class timer {
    // 所有记录
    public static $records = array();
    // 添加记录
    public static function add($label = "") {
        self::$records[] = array(microtime(), $label);
    }
    // 获取统计时间
    public static function get_total() {
        $count = count(self::$records);
        if(empty(self::$records) || $count < 2) {
            return 0;
        } else {
            $min = explode(" ", self::$records[0][0]);
            $max = explode(" ", self::$records[$count-1][0]);
            $res = round($max[0] + $max[1] - $min[0] - $min[1], 4);
            return $res;
        }
    }
    // 获取间隔时间
    public static function get_interval() {
        $count = count(self::$records);
        if(empty(self::$records) || $count < 2) {
            return array();
        } else {
            $ret = array();
            for($i = 1; $i < $count; $i++) {
                $min = explode(" ", self::$records[$i-1][0]);
                $max = explode(" ", self::$records[$i][0]);
                $res = round($max[0] + $max[1] - $min[0] - $min[1], 4);
                $ret[] = array($res, self::$records[$i][1]);
            }
            return $ret;
        }
    }
}

